package tech.yixiyun.framework.kuafu.config;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.databind.JsonNode;
import tech.yixiyun.framework.kuafu.kits.JSONKit;
import tech.yixiyun.framework.kuafu.kits.StringKit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Boolone
 * @date 2019/12/14
 */
public class AppConfig {

    private static final Logger LOGGER = LogManager.getLogger("yixiyun");
    /**
     * 配置,从default-config.json和 app-config.json中读取后合并的
     */
    private static JsonNode CONFIG = null;
    /**
     * 查询过的配置，在这里缓存。
     */
    private static final ConcurrentHashMap<String, Object> CONFIG_CACHE = new ConcurrentHashMap<>();

    static {
        LOGGER.info("******** 开始尝试加载配置文件 ********");
        loadDefaultConfig();
        loadAppConfig();

    }






    /**
     * 加载框架默认配置文件
     * @author Boolone
     * @date 2019/12/15
     * @param
     * @return void
     */
    private static void loadDefaultConfig() {
        //相对路径，才能读取到jar里的配置文件
        InputStream is = AppConfig.class.getResourceAsStream("/default-config.json");
        if (is == null) {
            throw new Error("框架默认配置文件(default-config.json)未找到");
        } else {
            try {
                CONFIG = JSONKit.toJsonObject(new String(IoUtil.readBytes(is)));
                LOGGER.info("加载【框架默认配置】成功");
            } finally {
                IoUtil.close(is);
            }
        }
    }
    /**
     * 加载项目自定义的配置文件
     * @author Boolone
     * @date 2019/12/15
     * @param
     * @return void
     */
    private static void loadAppConfig() {
        //有test 测试环境配置文件的话，优先用这个配置文件
        InputStream is = AppConfig.class.getResourceAsStream("/app-config-dev.json");
        String configType = null;
        if(is != null) {
            configType = "开发环境app配置";
            LOGGER.info("检测到【开发环境app配置(app-config-dev.json)】，加载中...");
        }

        if (is == null){
            configType = "生产环境app配置";
            is = AppConfig.class.getResourceAsStream("/app-config.json");
            if (is == null) {
                LOGGER.warn("未检测到app配置(app-config.json)");
            } else {
                LOGGER.info("检测到【生产环境app配置(app-config.json)】，加载中...");
                CONFIG = JSONKit.merge(CONFIG, is);
            }

        } else {
            CONFIG = JSONKit.merge(CONFIG, is);
        }
        LOGGER.info("加载【" +configType+"】成功");




    }

    /**
     * 根据key读取值，并转化为JsonNode
     * @param key
     * @return
     */
    public static JsonNode getAsTreeNode(String key) {
        return getAsObject(key, JsonNode.class);
    }

    /**
     * 根据key读取配置，并转化为制定指定的类型对象
     * @author Boolone
     * @date 2019/12/15
     * @param key
	 * @param clazz
     * @return T
     */
    public static <T> T getAsObject(String key, Class<T> clazz) {
        Object o = CONFIG_CACHE.get(key);

        if (o != null) {
            return (T) o;
        }

        T t = null;
        //从CONFIG中读取
        try {
            t = JSONKit.getValueAs(CONFIG, key, clazz);
        } catch (Exception e) {
            LOGGER.warn("从default_config解析 " + key + " 失败，请检查key和json数据格式是否匹配", e);
        }
        if (t != null) {
            CONFIG_CACHE.put(key, t);
        }

        return t;
    }

    /**
     * 根据key获取配置，并转成string类型
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @return java.lang.String
     */
    public static String getAsString(String key) {
        return getAsObject(key, String.class);
    }

    public static String getAsString(String key, String defaultValue) {
        String v = getAsString(key);
        return ObjectUtil.defaultIfNull(v, defaultValue);
    }

    /**
     * 根据key获取配置，并转成 Integer 类型
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @return Integer
     */
    public static Integer getAsInt(String key) {
        return getAsObject(key, Integer.class);
    }

    /**
     * 根据key取值，没值就用默认值
     * @param key
     * @param defaultValue
     * @return
     */
    public static Integer getAsInt(String key, int defaultValue) {
        Integer v = getAsInt(key);
        return ObjectUtil.defaultIfNull(v, defaultValue);
    }

    /**
     * 根据key获取配置，并转成Long类型
     * @param key
     * @return
     */
    public static Long getAsLong(String key) {
        return getAsObject(key, Long.class);
    }

    public static Long getAsLong(String key, long defaultValue) {
        Long v = getAsLong(key);
        return ObjectUtil.defaultIfNull(v, defaultValue);
    }

    /**
     * 根据key获取配置，并转成 Boolean 类型
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @return Boolean
     */
    public static Boolean getAsBoolean(String key) {
        return getAsObject(key, Boolean.class);
    }

    public static Boolean getAsBoolean(String key, Boolean defaultValue) {
        Boolean v = getAsBoolean(key);
        return ObjectUtil.defaultIfNull(v, defaultValue);
    }
    /**
     * 根据key获取配置，并转成 Double 类型
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @return Double
     */
    public static Double getAsDouble(String key) {
        return getAsObject(key, Double.class);
    }

    public static Double getAsDouble(String key, Double defaultValue) {
        Double v = getAsDouble(key);
        return ObjectUtil.defaultIfNull(v, defaultValue);
    }

    public static HashMap<String, String> getAsStringMap(String key) {
        Object o = CONFIG_CACHE.get(key);
        if (o != null) {
            return (HashMap<String, String>) o;
        }
        HashMap<String, String> map = (HashMap<String, String>) JSONKit.toStringMap(getAsTreeNode(key).toString());
        if (map != null) {
            CONFIG_CACHE.put(key, map);
        }
        return map;
    }

    /**
     * 根据key读取配置，并且将结果转成List
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @param clazz
     * @return T
     */
    public static <T>  List<T> getAsList(String key, Class<T> clazz) {
        Object o = CONFIG_CACHE.get(key);
        if (o != null) {
            return (List<T>) o;
        }
        List<T> list = null;

        try {
            list = JSONKit.getValueAsList(CONFIG, key, clazz);
        } catch (Exception e) {
            LOGGER.error("从config解析 " + key + " 失败，请检查key和json数据格式是否匹配", e);
        }
        if (list != null) {
            CONFIG_CACHE.put(key, list);
        }

        return list;
    }


    /**
     * 根据key读取配置，并转成List<String>
     * @author Boolone
     * @date 2019/12/16
     * @param key
     * @return java.util.List<java.lang.String>
     */
    public static List<String> getAsStringList(String key) {
        return getAsList(key, String.class);
    }


    /**
     * 根据key读取配置，并转成List<Integer>
     * @author Boolone
     * @date 2019/12/16
     * @param key
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getAsIntList(String key) {
        return getAsList(key, Integer.class);
    }

    /**
     * 根据key获取配置，并转成 Boolean 类型
     * @author Boolone
     * @date 2019/12/15
     * @param key
     * @return Boolean
     */
    public static <E extends Enum> E getAsEnum(String key, Class<E> clazz) {
        String value = getAsString(key);
        if (StringKit.isBlank(value)) return  null;
        return (E) Enum.valueOf(clazz, value);
    }




    /**
     * 手动设置某个配置，会覆盖配置文件中的配置。value类型一定要自己控制好
     * @param key
     * @param value
     */
    public static void set(String key, Object value) {
        CONFIG_CACHE.put(key, value);
    }


    /**
     * 清空所有的配置缓存
     */
    public static void reloadAllConfig() {
        CONFIG_CACHE.clear();
        loadAppConfig();
    }


}
